home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / pine / ccmd / stdact.c < prev    next >
Encoding:
C/C++ Source or Header  |  1988-08-19  |  22.7 KB  |  818 lines

  1. /*
  2.  Author: Andrew Lowry
  3.  
  4.  Columbia University Center for Computing Activities, July 1986.
  5.  Copyright (C) 1986, 1987, Trustees of Columbia University in the City
  6.  of New York.  Permission is granted to any individual or institution
  7.  to use, copy, or redistribute this software so long as it is not sold
  8.  for profit, provided this copyright notice is retained.
  9. */
  10. /* stdact 
  11. ** 
  12. ** Standard command action routines.  These actions are modeled after 
  13. ** those found in the TOPS-20 COMND jsys.  The standard actions defined 
  14. ** here will be used unless the programmer specifically provides an 
  15. ** overriding set of actions.  
  16. **/
  17.  
  18. #include "ccmdlib.h"        /* get ccmd package user symbols */
  19. #include "cmfncs.h"        /* and internal symbols */
  20.  
  21. /* Calling conventions for action routines:
  22. **
  23. ** Input arguments:
  24. **   fdblist - A pointer to the list of FDB's for this field.
  25. **   brk - The break character that caused this action.
  26. **   deferred - TRUE if this action is invoked in deferred mode (ie, the
  27. **     current input resulted in an incomplete parse) or immediate mode
  28. **     (immediately after the action character was typed).
  29. **
  30. ** Output arguments: None.
  31. ** Returns: Standard return code.  CMxDFR will cause the action to be
  32. **   invoked again later in deferred mode, as soon as some field results
  33. **   in an incomplete parse.  CMxRPT will cause a reparse.  CMxGO will
  34. **   cause a wakeup following the action, and CMxOK will indicate a
  35. **   successful action without a subsequent wakeup.
  36. **/
  37.  
  38. /* Forward declarations for action routines */
  39. int cmpact(), cmpact2(), pcmact(), hlpact(), cfmact(), delact();
  40. int begact(), wrdact(), fixact(), hstact(), bsact(), quoact();
  41. int indiract(), prevact(), nextact();
  42.  
  43. #ifdef TIOCSUST
  44. int loadav();
  45. #endif /* TIOCSUST */
  46.  
  47. /* Standard action table */
  48. int (*(stdact[128]))() = {
  49.     NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   pcmact, NULL,
  50.     bsact,  cmpact2,cfmact, NULL,   cfmact, cfmact, nextact,NULL,
  51.     prevact,   NULL,   fixact, NULL,   
  52. #ifdef TIOCSUST
  53.                         loadav,
  54. #else
  55.                         NULL,
  56. #endif /* TIOCSUST */
  57.                         begact, quoact, wrdact,
  58.     NULL,   NULL,   NULL,   cmpact, NULL,   NULL,   NULL,   NULL,
  59.     NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
  60.     NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
  61.     NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
  62.     NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   hlpact,
  63.     indiract,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
  64.     NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
  65.     NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
  66.     NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
  67.     NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
  68.     NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
  69.     NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
  70.     NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   delact
  71. };
  72.  
  73. /* miscellaneous global declarations */
  74.  
  75. #if unix
  76. char cmcont = '\\';        /* continuation character (used by cfmact) */
  77. #else
  78. char cmcont = '-';        /* TOPS-20's continuation character */
  79. #endif
  80.  
  81.  
  82.  
  83. /* cmpact
  84. ** 
  85. ** Purpose:
  86. **   Action routine for an ESCAPE character.  First, cmdflt is called
  87. **   to attempt to stuff a default string into the command line.  If
  88. **   that fails, cmcplt is called to attempt completion on the current
  89. **   input.  This is a deferred action, and always causes wakeup after
  90. **   success.
  91. **/
  92.  
  93. PASSEDSTATIC
  94. int 
  95. cmpact(fdblist,brk,deferred)
  96. fdb *fdblist;
  97. char brk;
  98. int deferred;
  99. {
  100.   if (!deferred)
  101.     return(CMxDFR);            /* wait for deferred mode */
  102.  
  103.   if (cmcsb._cmflg & CM_CMT) {        /* if inside a comment, just beep */
  104.     cmputc(BELL,cmcsb._cmoj);        /* beep if they asked us to */
  105.     cmxflsh();
  106.     return(CMxOK);
  107.   }
  108.  
  109.   if (cmdflt(fdblist) == CMxOK) {    /* first try filling a default */
  110.     cmcsb._cmflg |= CM_PFE;        /* wants wakeup -activate noise words*/
  111.     return(CMxGO);            /* wakeup on success */
  112.   }
  113.   else
  114.     return(cmcplt(TRUE));        /* otherwise try full completion */
  115. }
  116.  
  117.  
  118. /* cmpact2
  119. ** 
  120. ** Purpose:
  121. **   Action routine for a TAB character.  We only do this if input is
  122. **   coming from a TTY.  This is so that we won't choke on tabs in 
  123. **   Take and indirect files.  First, cmdflt is called
  124. **   to attempt to stuff a default string into the command line.  If
  125. **   that fails, cmcplt is called to attempt completion on the current
  126. **   input.  This is a deferred action, and always causes wakeup after
  127. **   success.
  128. **/
  129.  
  130. PASSEDSTATIC int 
  131. cmpact2(fdblist,brk,deferred)
  132. fdb *fdblist;
  133. char brk;
  134. int deferred;
  135. {
  136.   if (!(cmcsb._cmflg & CM_TTY)) {
  137.       cmsti1(brk);
  138.       return(CMxOK);
  139.   }
  140.   return(cmpact(fdblist,brk,deferred));
  141. }
  142.  
  143. /* pcmact
  144. **
  145. ** Purpose:
  146. **   Action to perform partial completion on the current input.
  147. **/
  148.  
  149. PASSEDSTATIC int
  150. pcmact(fdblist,brk,deferred)
  151. fdb *fdblist;
  152. char brk;
  153. int deferred;
  154. {
  155.   if (!deferred)
  156.     return(CMxDFR);            /* wait for deferred mode */
  157.  
  158.   if (cmcsb._cmflg & CM_CMT) {        /* if inside a comment, just beep */
  159.     cmputc(BELL,cmcsb._cmoj);        /* beep if they asked us to */
  160.     cmxflsh();
  161.     return(CMxOK);
  162.   }
  163.  
  164.   if (cmpdflt(fdblist) == CMxOK) {    /* first try filling a default */
  165.     return(CMxGO);            /* wakeup on success */
  166.   }
  167.   else
  168.     return(cmcplt(FALSE));        /* use standard utility */
  169. }
  170.  
  171. /* hlpact
  172. **
  173. ** Purpose:
  174. **   Action routine for a help request.
  175. **/
  176.  
  177. PASSEDSTATIC int 
  178. hlpact(fdblist,brk,deferred)
  179. fdb *fdblist;
  180. char brk;
  181. int deferred;
  182. {
  183.   if (!deferred)
  184.     return(CMxDFR);            /* wait for deferred mode */
  185.  
  186.   if (cmcsb._cmflg & CM_CMT) {        /* if inside a comment */
  187.     cmsti1(brk,0);
  188.     return(CMxOK);
  189.   }
  190.  
  191.   return(cmhelp(fdblist,cmcsb._cmbkc));    /* use std help utility */
  192. }
  193.  
  194. /* cfmact
  195. **
  196. ** Purpose:
  197. **   Action routine for a confirmation.  Stuff a newline, and set the
  198. **   CM_CFM flag in the CSB.  Also, a newline character is set into
  199. **   field _cmbkc in the CSB, to match the newline that got stuffed
  200. **   into the buffer.  If the confirmation character was formfeed,
  201. **   clear the screen.  If the confirmation character was carriage
  202. **   return or newline, and if there is a continuation character
  203. **   at the end of the unparsed input buffer, no action is taken,
  204. **   but a newline is stuffed with CC_SKP flag on, and the CC_CSK
  205. **   flag is added to the hyphen (to make it skip conditionally on
  206. **   the newline's presence).
  207. **/
  208.  
  209.  
  210. PASSEDSTATIC int
  211. cfmact(fdblist,brk,deferred)
  212. fdb *fdblist;
  213. char brk;
  214. int deferred;
  215. {
  216.   int ret;
  217.   int *end;                /* end of current input */
  218.  
  219.   if (cmcsb._cminc > 0) {        /* is there unparsed input? */
  220.     end = cmcsb._cmptr + cmcsb._cminc - 1; /* point to last char */
  221.     if ((*end & CC_QCH) == cmcont) {    /* last char continuation char? */
  222.                     /*  (fails if quoted) */
  223.       *end |= CC_CSK;            /* make it conditionally skipped */
  224.       ret = cmsti1(NEWLINE,CC_SKP);    /* and stuff a skipped newline */
  225.       return(ret);            /* no wakeup */
  226.     }
  227.   }
  228.  
  229.   if (!deferred)
  230.       return(CMxDFR);
  231.  
  232.   if (cmcsb._cmflg & CM_CMT) {        /* if inside a comment */
  233.       cmcsb._cmflg &= ~CM_CMT;        /* then turn off the comment */
  234.   }
  235.       
  236.   if (cmcsb._cmflg2 & CM_IND) {
  237.       cmsti1(' ',0 );
  238.       return(CMxOK);
  239.   }
  240.  
  241.   ret = cmsti1(NEWLINE,0);        /* stuff newline */
  242.   if (ret != CMxOK)
  243.     return(ret);            /* propagate problems */
  244.  
  245.   cmcsb._cmflg |= CM_CFM;        /* set confirmed flag */
  246.   cmcsb._cmbkc = NEWLINE;        /* and set confirming char */
  247.   if ((brk == FORMFEED) &&
  248.       (cmcsb._cmflg & CM_CRT) &&
  249.       !(cmcsb._cmflg & CM_NEC)
  250.      )
  251.     cmxcls();                       /* clear the screen for a formfeed */
  252.   remember();                /* add to cmdline history */
  253.   return(CMxGO);            /* now wake them up */
  254. }
  255.  
  256. /* delact
  257. **
  258. ** Purpose:
  259. **   Erase back to and including the last non-hidden character in the
  260. **   command buffer.  If erasing continues into the parsed region, a
  261. **   reparse is signalled.
  262. **/
  263.  
  264. PASSEDSTATIC int
  265. delact(fdblist,brk,deferred)
  266. fdb *fdblist;
  267. char brk;
  268. int deferred;
  269. {
  270.   int *cp;                /* for scanning the command buffer */
  271.   int eralen;                /* number of characters to erase */
  272.  
  273.   cp = cmcsb._cmptr + cmcsb._cminc;     /* point to end of buffer */
  274.   while (cp-- != cmcsb._cmbfp) {     /* loop over all the chars */
  275.     if ((*cp & CC_HID) == 0)
  276.       break;                /* found a non-hidden character */
  277.   }
  278.   cp++;                    /* point to last nonhidden char */
  279.  
  280.   if (cp != cmcsb._cmbfp)        /* if there are nonhidden chars */
  281.     cp--;                /* consume the last one */
  282.  
  283.   eralen = (cmcsb._cmptr - cp) + cmcsb._cminc; /* get # of chars erased */
  284.   if (eralen == 0) {
  285.     if (cmcsb._cmflg & CM_TTY)
  286.       cmputc(BELL,cmcsb._cmoj);    /* beep if nothing */
  287.     return(CMxOK);
  288.   }
  289.  
  290.   if (cmcsb._cmflg & CM_CRT)
  291.     cmcsb._cmcol = cmxera(eralen,FALSE); /* erase the characters */
  292.   else if ((*cp & (CC_HID | CC_NEC)) == 0) { 
  293.     cmechx('\\');            /* give erase marker on hardcopy */
  294.     cmechx((char) (*cp) & CC_CHR);
  295.   }
  296.   cmcsb._cminc -= eralen;        /* update CSB counters */
  297.   cmcsb._cmcnt += eralen;
  298.   if (cmcsb._cminc <= 0) {        /* erased back to parsed data? */
  299.     cmcsb._cmptr += cmcsb._cminc;    /* yup, backup parsed pointer */
  300.     cmcsb._cminc = 0;            /* no unparsed chars */
  301.     return(CMxRPT);            /* and call for reparse */
  302.   }
  303.   else
  304.    return(CMxOK);            /* else no reparse */
  305. }
  306.  
  307. /* wrdact
  308. **
  309. ** Purpose:
  310. **   Erase the last word of command line input.  Words consist of letters
  311. **   and digits.  All other characters are delimiters.  This action erases
  312. **   the last nonhidden character in the input, and then continues erasing
  313. **   until it is about to erase a delimiter.
  314. **/
  315.  
  316. PASSEDSTATIC int
  317. wrdact(fdblist,brk,deferred)
  318. fdb *fdblist;
  319. char brk;
  320. int deferred;
  321. {
  322.   int *cp;                /* pointer to deletion site */
  323.   int cc;                /* character under examination */
  324.   char c;
  325.   int eralen;                /* # of chars erased */
  326.  
  327.   cp = cmcsb._cmptr + cmcsb._cminc;     /* point to end of buffer */
  328.   while (cp-- != cmcsb._cmbfp) {     /* loop over all the chars */
  329.     if ((*cp & CC_HID) == 0)
  330.       break;                /* found a non-hidden character */
  331.   }
  332.   cp++;                    /* point to last nonhidden char */
  333.  
  334.   if (cp != cmcsb._cmbfp)
  335.     cp--;                /* erase at least 1 nonhidden char */
  336.   while (cp-- != cmcsb._cmbfp) {    /* search for nonhidden delimiter */
  337.     c = (cc = *cp) & CC_CHR;        /* get next char */
  338.     if (((cc & CC_HID) == 0) &&        /* nonhidden? */
  339.         ((c < '0') ||            /* and not a letter or digit? */
  340.      ((c > '9') && (c < 'A')) ||
  341.      ((c > 'Z') && (c < 'a')) ||
  342.      (c > 'z')
  343.     )
  344.        )
  345.       break;                /* yup, stop looking */
  346.   }
  347.   cp++;                    /* point to char after break */
  348.  
  349.   eralen = (cmcsb._cmptr - cp) + cmcsb._cminc; /* get # of chars erased */
  350.   if (eralen == 0) {
  351.     if (cmcsb._cmflg & CM_TTY)
  352.       cmputc(BELL,cmcsb._cmoj);     /* beep if nothing */
  353.     return(CMxOK);
  354.   }
  355.  
  356.   if (cmcsb._cmflg & CM_CRT)
  357.     cmcsb._cmcol = cmxera(eralen,FALSE); /* erase the characters */
  358.   else
  359.     cmechx('_');            /* print underscore on hardcopy */
  360.   cmcsb._cminc -= eralen;        /* update CSB counters */
  361.   cmcsb._cmcnt += eralen;
  362.   if (cmcsb._cminc <= 0) {        /* erased back to parsed data? */
  363.     cmcsb._cmptr += cmcsb._cminc;    /* yup, backup parsed pointer */
  364.     cmcsb._cminc = 0;            /* no unparsed chars */
  365.     return(CMxRPT);            /* and call for reparse */
  366.   }
  367.   else
  368.    return(CMxOK);            /* else no reparse */
  369. }
  370.  
  371.  
  372. /* begact
  373. **
  374. ** Purpose:
  375. **   Erase the entire command line, back to the last unhidden newline
  376. **   character.  If the last character is a newline, it is erased, and 
  377. **   the prior line is erased back to the previous newline.
  378. **   If parsed characters are deleted, a reparse is called for.
  379. **/
  380.  
  381. PASSEDSTATIC int
  382. begact(fdblist,brk,deferred)
  383. fdb *fdblist;
  384. char brk;
  385. int deferred;
  386. {
  387.   int *cp;                /* pointer to deletion site */
  388.   int cc;                /* character under examination */
  389.   char c;
  390.   int eralen;                /* # of chars erased */
  391.  
  392.   cp = cmcsb._cmptr + cmcsb._cminc;     /* point to end of buffer */
  393.   while (cp-- != cmcsb._cmbfp) {     /* loop over all the chars */
  394.     if ((*cp & CC_HID) == 0)
  395.       break;                /* found a non-hidden character */
  396.   }
  397.   cp++;                    /* point to last nonhidden char */
  398.  
  399.   if (cp != cmcsb._cmbfp)
  400.     cp--;                /* erase at least 1 nonhidden char */
  401.   while (cp-- != cmcsb._cmbfp) {    /* search for nonhidden newline */
  402.     c = (cc = *cp) & CC_CHR;        /* get next char */
  403.     if (((cc & CC_HID) == 0) && (c == NEWLINE)) /* nonhidden newline? */
  404.       break;                /* yup, stop looking */
  405.   }
  406.   cp++;                    /* point to char after break */
  407.  
  408.   eralen = (cmcsb._cmptr - cp) + cmcsb._cminc; /* get # of chars erased */
  409.  
  410.   if (cmcsb._cmflg & CM_CRT)
  411.     cmcsb._cmcol = cmxera(eralen,TRUE); /* erase the characters */
  412.   else {
  413.     cmxputs("^U");            /* signal line kill on hardcopy */
  414.     cmxnl();                /* move to a new line */
  415.     if (cp == cmcsb._cmbfp)        /* killed prompt line? */
  416.       cmxputs(cmcsb._cmrty);        /* then reprompt */
  417.   }
  418.   cmcsb._cminc -= eralen;        /* update CSB counters */
  419.   cmcsb._cmcnt += eralen;
  420.   if (cmcsb._cminc <= 0) {        /* erased back to parsed data? */
  421.     cmcsb._cmptr += cmcsb._cminc;    /* yup, backup parsed pointer */
  422.     cmcsb._cminc = 0;            /* no unparsed chars */
  423.     return(CMxRPT);            /* and call for reparse */
  424.   }
  425.   else
  426.    return(CMxOK);            /* else no reparse */
  427. }
  428.  
  429. /* fixact
  430. **
  431. ** Purpose:
  432. **   Refresh the display of the current line of text, back to the
  433. **   last unhidden newline character.  If there is no newline, refresh the
  434. **   prompt and all the current text.  If the last character in the
  435. **   buffer is a newline, the previous line is refreshed.
  436. **/
  437.  
  438. PASSEDSTATIC int
  439. fixact(fdblist,brk,deferred)
  440. fdb *fdblist;
  441. char brk;
  442. int deferred;
  443. {
  444.   int *cp;                /* pointer into buffer */
  445.   int cc;                /* character under examination */
  446.   char c;
  447.   int reflen;                /* # of chars refreshed */
  448.  
  449.   cp = cmcsb._cmptr + cmcsb._cminc;     /* point to end of buffer */
  450.   while (cp-- != cmcsb._cmbfp) {     /* loop over all the chars */
  451.     if ((*cp & CC_HID) == 0)
  452.       break;                /* found a non-hidden character */
  453.   }
  454.   cp++;                    /* point to last nonhidden char */
  455.  
  456.   if (cp != cmcsb._cmbfp)
  457.     cp--;                /* refresh at least 1 nonhidden chr */
  458.   while (cp-- != cmcsb._cmbfp) {    /* search for nonhidden newline */
  459.     c = (cc = *cp) & CC_CHR;        /* get next char */
  460.     if (((cc & CC_HID) == 0) && (c == NEWLINE)) /* nonhidden newline? */
  461.       break;                /* yup, stop looking */
  462.   }
  463.   cp++;                    /* point to char after break */
  464.  
  465.   reflen = (cmcsb._cmptr - cp) + cmcsb._cminc; /* get # of chars to refresh */
  466.  
  467.   if (cmcsb._cmflg & CM_CRT)
  468.     cmcsb._cmcol = cmxera(reflen,TRUE); /* erase the characters from screen */
  469.   else {
  470.     cmxputs("^R");            /* signal line kill on hardcopy */
  471.     cmxnl();                /* move to a new line */
  472.     if (cp == cmcsb._cmbfp)        /* killed prompt line? */
  473.       cmxputs(cmcsb._cmrty);        /* then reprompt */
  474.   }
  475.   while (reflen-- > 0) {        /* retype buffer contents */
  476.     c = (cc = *cp++) & CC_CHR;        /* get next char */
  477.     if ((cc & CC_NEC) == 0)        /* character originally echoed? */
  478.       cmechx(c);            /* yup, do it again */
  479.   }
  480.   return(CMxOK);
  481. }
  482.  
  483.  
  484.  
  485. /* hstact
  486. **
  487. ** Purpose:
  488. **   Action routine to reinstate the command buffer from a previous
  489. **   failed parse.  If the CM_DRT flag is off in the CSB, then the
  490. **   prior input text is still intact.  That text is redisplayed, and
  491. **   the CSB pointers are set so that all of the text is considered
  492. **   unparsed.  Then a no-wakeup return is made (a wakeup would probably
  493. **   just cause the same parse failure again).
  494. **/
  495.  
  496. PASSEDSTATIC int
  497. hstact(fdblist,brk,deferred)
  498. fdb *fdblist;
  499. char brk;
  500. int deferred;
  501. {
  502.   int *cp;                /* pointer into command buffer */
  503.   int count,i;                /* number of chars to reinstate */
  504.  
  505.   if (!deferred)
  506.       return(CMxDFR);
  507.   if (cmcsb._cmflg & CM_DRT)
  508.     return(CMxOK);            /* nothing to do if buffer is dirty */
  509.   count = cmcsb._cmhst - cmcsb._cmbfp;    /* count buffered chars */
  510.   cp = cmcsb._cmbfp;            /* point to beginning of buffer */
  511.   for (i = 0; i < count; i++) {
  512.       if ((cp[i] & CC_CHR) == NEWLINE) {
  513.       count = i;
  514.       break;
  515.       }
  516.   }
  517.   cmcsb._cminc = count;            /* this many chars now to parse */
  518.   cmcsb._cmcnt -= count;        /* count their presence */
  519.   cmcsb._cmflg |= CM_DRT;        /* now the buffer is dirty */
  520.   while (count-- > 0)             /* step through the buffer */
  521.     if (((*cp) & CC_NEC) == 0)        /* originally echoed? */
  522.       cmechx((char) (*cp++) & CC_CHR);    /* then echo it now */
  523.     else
  524.       cp++;                /* else just move on */
  525.   return(CMxOK);
  526. }
  527.  
  528.  
  529.  
  530. /* bsact
  531. **
  532. ** Purpose:
  533. **   Action routine for a backspace.  If the buffer is dirty, invoke the
  534. **   single character deletion action.  Otherwise, invoke the history
  535. **   action.
  536. **/
  537.  
  538. PASSEDSTATIC int
  539. bsact(fdblist,brk,deferred)
  540. fdb *fdblist;
  541. char brk;
  542. int deferred;
  543. {
  544.   if (cmcsb._cmflg & CM_DRT)        /* buffer dirty? */
  545.     return(delact(fdblist,brk,deferred)); /* delete one char */
  546.   else
  547.     return(hstact(fdblist,brk,deferred)); /* otherwise try history */
  548. }
  549.  
  550.  
  551. /* quoact
  552. **
  553. ** Purpose:
  554. **   Enter the next character into the buffer with its quote flag
  555. **   turned on, so it will be treated as a normal character regardless
  556. **   of any handling it would normally receive.
  557. **/
  558.  
  559. PASSEDSTATIC int
  560. quoact(fdblist,brk,deferred)
  561. fdb *fdblist;
  562. char brk;
  563. int deferred;
  564. {
  565.   char c;            /* quoted character */
  566.   int ret;            /* result code from input operation */
  567.   
  568.   ret = cmgetc(&c,cmcsb._cmij); /* get another character */
  569.   if (ret != CMxOK)
  570.     return(ret);        /* propagate problems */
  571.   ret = cmsti1(c,CC_QUO);    /* enter the charcter, quoted */
  572.   return(ret);            /* CMxOK normally -- no wakeup */
  573. }
  574.  
  575. #define MAXINDIRECTIONS 25
  576. struct indir_stack_ent {
  577.     FILE *oldij, *oldoj;
  578.     int (*olderr)();
  579. };
  580.  
  581. struct indir_stack {
  582.     struct indir_stack_ent data[MAXINDIRECTIONS];
  583.     int sptr;
  584. };
  585.  
  586. static struct indir_stack indstack;
  587.  
  588. ind_oldfds() {
  589.     static int first = TRUE;
  590.     if (first) {
  591.     indstack.sptr = -1;
  592.     first = FALSE;
  593.     }
  594.     if (indstack.sptr >= MAXINDIRECTIONS) {
  595.     cmerjmp(CMxSOF);
  596.     }
  597.     indstack.sptr++;
  598.     indstack.data[indstack.sptr].oldij = cmcsb._cmij;
  599.     indstack.data[indstack.sptr].oldoj = cmcsb._cmoj;
  600.     indstack.data[indstack.sptr].olderr = cmcsb._cmerh;
  601. }
  602.  
  603. cmindend() {
  604.     if (indstack.sptr < 0)  {
  605.     cmcsb._cmflg2 &= ~CM_IND;
  606.     cmerjmp(CMxSUF);
  607.     }
  608.     fclose(cmcsb._cmij);
  609.     if (cmcsb._cmoj) 
  610.     fclose(cmcsb._cmoj);
  611.     cmseti(indstack.data[indstack.sptr].oldij,
  612.        indstack.data[indstack.sptr].oldoj, cmcsb._cmej);
  613.     cmcsb._cmerh = indstack.data[indstack.sptr].olderr;
  614.     indstack.sptr--;
  615.     if (indstack.sptr < 0)
  616.     cmcsb._cmflg2 &= ~CM_IND;
  617. }
  618.  
  619. cminderr(code) int code; {
  620.     cmindend();                /* turn off indirection */
  621.     cmerjmp(code);            /* call old error handler */
  622. }
  623.  
  624. PASSEDSTATIC
  625. int indiract(fdblist, brk, deferred, flags)
  626. fdb *fdblist;
  627. char brk;
  628. int deferred,flags;
  629. {
  630.   char c;            /* quoted character */
  631.   int ret;            /* result code from input operation */
  632.   FILE *f;
  633.   
  634.   static fdb filfdb = { _CMFIL, CM_SDH, NULL, NULL,
  635.                 "Filename for indirect file", NULL, NULL };
  636.   static fdb cfmfdb = { _CMCFM, 0, NULL, NULL, NULL, NULL, NULL };
  637.   static brktab chrbrk = {
  638.       {
  639.       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  640.       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  641.       },
  642.       {
  643.       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  644.       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  645.       },
  646.   };
  647.   static fdb chrfdb = { _CMCHAR, CM_SDH, NULL, NULL,
  648.                  "Filename for indirect file", NULL, &chrbrk };
  649.   static int entered = FALSE;
  650.   fdb *used;
  651.   pval pv;
  652.   static char *fname = NULL;
  653.   char *malloc();
  654.   int i;
  655.  
  656.   if (cmcsb._cmflg & CM_CMT) {        /* if inside a comment,  */
  657.       cmsti1(brk,0);            /* just insert the break char */
  658.       return(CMxOK);
  659.   }
  660.  
  661.   if (fname != NULL)            /* free up old filename */
  662.       free(fname);
  663.  
  664.   if (cmcsb._cmflg2 & CM_NIN) { /* no indirections allowed  */
  665.       cmsti1(brk,0);            /* just insert the break char */
  666.       return(CMxOK);            /* and go home */
  667.   }
  668.  
  669.   if (!deferred) {
  670.     return(CMxDFR);            /* wait for deferred mode */
  671.   }
  672.  
  673.   if (!(flags & CC_ACT))
  674.       cmsti1(brk,CC_ACT);            /* make it show up. */
  675.   cmcsb._cmflg &= ~CM_ACT;
  676.  
  677.   for(i = 0; i < 16; i++) {
  678.       chrbrk._br1st[i] = 0xff;
  679.       chrbrk._brrest[i] = 0xff;
  680.   }
  681.   chrbrk._br1st[brk/8] &= ~(1<<(7-(brk%8))); /* turn off the bit */
  682.   chrbrk._brrest[brk/8] &= ~(1<<(7-(brk%8))); /* turn off the bit */
  683.   parse(&chrfdb, &pv, &used);
  684.   parse(&filfdb, &pv, &used);        /* parse filename */
  685.   fname = malloc(strlen(pv._pvfil[0]) + 1); /* copy it */
  686.   strcpy(fname,pv._pvfil[0]);
  687.   parse(&cfmfdb, &pv, &used);        /* parse a confirm. */
  688.   
  689.   ind_oldfds();
  690.   f = fopen(fname,"r");
  691.   if (f == NULL) {
  692.       cmcsb._cmerr = 0;
  693.       indstack.sptr--;
  694.       cmerjmp();
  695.   }
  696.   cmseti(f,NULL,cmcsb._cmej);
  697.   cmcsb._cmerh = cminderr;
  698.   cmcsb._cmflg2 |= CM_IND;        /* turn on indirection flag */
  699.   return(CMxOK);
  700. }
  701.  
  702. #ifdef TIOCSUST
  703. PASSEDSTATIC int
  704. loadav(fdblist,brk,deferred)
  705. {
  706.     int x,y,z;
  707.     int ret;
  708.     int i;
  709.  
  710.     ioctl(fileno(cmcsb._cmij),TIOCGETD,&y); /* get line discipline */
  711.     ioctl(fileno(cmcsb._cmij),TIOCSETD,&x); /* set to new line discipline */
  712.     if (!ioctl(fileno(cmcsb._cmij),TIOCSUST,&x)) { /* show the load */
  713.     cmxprintf("%s", cmcsb._cmrty);
  714.     for (i = 0; i < cmcsb._cminc + cmcsb._cmptr - cmcsb._cmbfp; i++)
  715.         cmxputc(cmcsb._cmbfp[i] & 0x7f);
  716.     fflush(cmcsb._cmoj);
  717.     }
  718.     ioctl(fileno(cmcsb._cmij),TIOCSETD,&y); /* restore line disc. */
  719.     return(CMxOK);            /* all done. */
  720. }
  721.  
  722. #endif /* TIOCSUST */
  723.  
  724.  
  725. /* 
  726.  * routines to implement command line history.
  727.  */
  728.  
  729.  
  730. /* 
  731.  * add a line to the command line history (if we have one).
  732.  */
  733. remember() {
  734.     cmhist *h = cmcsb._cmhist;
  735.     int i,len,j;
  736.     if (h == NULL) {
  737.     cmhst(10);
  738.     h = cmcsb._cmhist;
  739.     }
  740.     if (h->enabled == FALSE || h->len == 0)
  741.     return;
  742.     i =  h->next % h->len;
  743.     len = cmcsb._cmptr - cmcsb._cmbfp + cmcsb._cminc - 1;
  744.     if (len == 0) return;
  745.     h->bufs[i].buf = (int *)cmrealloc(h->bufs[i].buf, len * sizeof(int));
  746.     for(j = 0; j < len; j++) {
  747.     h->bufs[i].buf[j] = cmcsb._cmbfp[j];
  748.     }
  749.     h->bufs[i].len = len;
  750.     h->next++;
  751.     h->next %= h->len;
  752.     h->current = h->next;
  753.     if (h->bufs[h->next].buf) {
  754.     free(h->bufs[h->next].buf);
  755.     h->bufs[h->next].buf = NULL;
  756.     h->bufs[h->next].len = 0;
  757.     }
  758. }
  759.  
  760. PASSEDSTATIC int 
  761. nextact(fdblist,brk,deferred)
  762. fdb *fdblist;
  763. char brk;
  764. int deferred;
  765. {
  766.     cmhist *h = cmcsb._cmhist;
  767.     int i;
  768.     int next;
  769.     if (h == NULL || h->len == 0) {
  770.     cmputc(BELL,cmcsb._cmoj);
  771.     cmxflsh();
  772.     return(CMxOK);
  773.     }
  774.     next = (h->current + h->len + 1) % h->len;
  775.     if (h->bufs[next].buf == NULL || h->next == h->current) {
  776.     cmputc(BELL,cmcsb._cmoj);
  777.     cmxflsh();
  778.     return(CMxOK);
  779.     }
  780.     h->current = next;
  781.     begact(fdblist,brk,deferred);
  782.     for( i= 0; i < h->bufs[next].len; i++)
  783.     cmsti1(h->bufs[next].buf[i] & CC_CHR, h->bufs[next].buf[i] & ~CC_CHR);
  784.     return(CMxOK);
  785. }
  786.  
  787.  
  788. PASSEDSTATIC int 
  789. prevact(fdblist,brk,deferred)
  790. fdb *fdblist;
  791. char brk;
  792. int deferred;
  793. {
  794.     cmhist *h = cmcsb._cmhist;
  795.     int i;
  796.     int prev;
  797.  
  798.     if (h == NULL || h->len == 0) {
  799.     cmputc(BELL,cmcsb._cmoj);
  800.     cmxflsh();
  801.     return(CMxOK);
  802.     }
  803.     prev = (h->current + h->len - 1) % h->len;
  804.  
  805.     if (h->bufs[prev].buf == NULL) {
  806.     cmputc(BELL,cmcsb._cmoj);
  807.     cmxflsh();
  808.     return(CMxOK);
  809.     }
  810.     h->current = prev;
  811.     begact(fdblist,brk,deferred);
  812.     for( i= 0; i < h->bufs[prev].len; i++)
  813.     cmsti1(h->bufs[prev].buf[i] & CC_CHR, h->bufs[prev].buf[i] & ~CC_CHR);
  814.     return(CMxOK);
  815. }
  816.  
  817.  
  818.